
import RigidBody from './rigid-body';
import BroadPhase from './broad-phase';
import CollisionDispatcher from './collision-dispatcher';
import CONST from './collision-const';

/**
 * 碰撞世界（碰撞检测范围容器）
 *  @param config {CollisionWorldConfig}
 */
export default class CollisionWorld{
    constructor(config={}){
        this._config=config;
        this._init();
    }

    /**
     * 激活或停止检测
     * @param bol
     */
    set active(bol){
        this._props.active=bol;
    }

    /**
     * 获取碰撞事件发生器
     * @returns {null|CollisionDispatcher|CollisionDispatcher}
     */
    get dispatcher(){
        return this._dispatcher;
    }

    /**
     * 开启或关闭碰撞事件发生器
     * @param bol
     */
    set stopEventDispatching(bol){
        this._dispatcher.active=!bol;
    }

    /**
     * 立即强制更新一次
     * @param bol
     */
    set forceUpdate(bol){
        if(!bol)return;
        this.onUpdate(1);
    }

    /**
     * 更新碰撞状态（参数无效）
     * @param deltaTime
     */
    set update(deltaTime){
        if(!this._props.active)return;
        this.onUpdate(deltaTime);
    }

    /**
     * 更新所有碰撞体
     * @param deltaTime
     */
    onUpdate(deltaTime){
        this.updateRigidBody();
    }

    /**
     * 强制更新所有碰撞体
     * @param rigidBodies
     */
    forceUpdateRigidBody(...rigidBodies){
        let rbs=rigidBodies.length===0?this._rigidBodies:rigidBodies;
        let temp=[];
        for(let rb of rbs){
            temp.push(...rb.userData.rigid.colliders);
        }
        this._broadphase.updateCollider(...temp);
    }

    /**
     * 更新碰撞体
     * @param rigidBodies
     */
    updateRigidBody(...rigidBodies){
        let rbs=rigidBodies.length===0?this._rigidBodies:rigidBodies;
        let temp=[];
        for(let rb of rbs){
            if(rb.isStatic)continue;
            temp.push(...rb.userData.rigid.colliders);
        }
        this._broadphase.updateCollider(...temp);
    }

    /**
     * 创建碰撞体
     * @param three_obj {Object3D}
     * @param collider_pos_quat {[collider,position,quaternion]}
     */
    createRigidBody(three_obj,...collider_pos_quat){
        let rigid=new RigidBody();
        rigid.object=three_obj;
        for(let spp of collider_pos_quat){
            rigid.addCollider(spp[0]);
            this._broadphase.addCollider(spp[0]);
            if(spp[1])spp[0].position.copy(spp[1]);
            if(spp[2])spp[0].quaternion.copy(spp[2]);
        }
        this._rigidBodies.push(three_obj);
        return rigid;
    }

    /**
     * 移除碰撞体
     * @param three_obj {...Object3D}
     */
    removeRigidBody(...three_obj){
        for(let o of three_obj){
            let index=this._rigidBodies.findIndex((_o)=>_o.uuid===o.uuid);
            if(index===-1)continue;
            this._broadphase.removeCollider(...o.userData.rigid.colliders);
            o.userData.rigid.dispose();
            this._rigidBodies.splice(index,1);
        }
    }

    /**
     * 清除碰撞体
     */
    clearRigidBody(){
        for(let o of this._rigidBodies){
            let index=this._rigidBodies.findIndex((_o)=>_o.uuid===o.uuid);
            if(index===-1)continue;
            o.userData.rigid.dispose();
        }
        this._broadphase.clearCollider();
        this._rigidBodies=[];
    }

    _initialize(){
        this._broadphase.onContactEnter=(collider)=>{
            collider.contactState=CONST.CONTACT_STATE_ENTER;
            this._dispatcher.dispatchContactEnter(collider);
        };
        this._broadphase.onContactStay=(collider)=>{
            collider.contactState=CONST.CONTACT_STATE_STAY;
            this._dispatcher.dispatchContactStay(collider);
        };
        this._broadphase.onContactExit=(collider)=>{
            collider.contactState=CONST.CONTACT_STATE_EXIT;
            this._dispatcher.dispatchContactExit(collider);
        };
    }
    _init(){
        this._initProps();
        this._initVariable();
        this._initComponents();
        this._initialize();
    }
    _initProps(){
        this._props={
            active:this._config.active!==undefined?this._config.active:true,
        };
    }
    _initVariable(){
        this._dispatcher=null;
        this._broadphase=null;

        this._rigidBodies=[];
    }
    _initComponents(){
        this._initDispatcher();
        this._initBroadphase();
    }
    _initDispatcher(){
        this._dispatcher=new CollisionDispatcher();
    }
    _initBroadphase(){
        this._broadphase=new BroadPhase(this._config);
    }
}